package cn.mothin.frame.core.base;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import cn.mothin.frame.core.annotation.Entity;
import cn.mothin.frame.core.db.SqlHelper;
import cn.mothin.frame.core.exception.SystemException;
import cn.mothin.frame.core.interfaces.vo.IQueryPage;
import cn.mothin.frame.util.JsonUtil;
import cn.mothin.frame.util.StringUtil;

public class BaseDao<T> {
    protected Class<T> entityClass;
    protected String tableName;
    protected List<Field> fields = new ArrayList<Field>();
    @Autowired
    protected SqlHelper sqlHelper;
    @Autowired
    private JsonUtil jsonUtil;

    @SuppressWarnings("unchecked")
    public BaseDao() {
        entityClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
        if (entityClass.isAnnotationPresent(Entity.class)) {
            Entity entity = entityClass.getAnnotation(Entity.class);
            tableName = entity.tableName();
            if (tableName == null || tableName.length() == 0) {
                tableName = entityClass.getSimpleName();
            }

            Field[] fs = entityClass.getDeclaredFields();
            for (Field f : fs) {
                if (Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
                fields.add(f);
            }

        } else {
            throw new SystemException();
        }
    }

    private boolean isPK(String fieldName) {
        if (fieldName.equals("id")) {
            return true;
        }
        return false;
    }

    private Object getIdValue(T entity) {
        try {
            Field field = entityClass.getDeclaredField("id");
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            return field.get(entity);
        } catch (Exception e) {
            throw new SystemException();
        }
    }

    private Object getFieldValue(Field field, T entity) {
        try {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            return field.get(entity);
        } catch (Exception e) {
            throw new SystemException();
        }
    }

    private Object getFieldValue(String fieldName, T entity) {
        try {
            Field field = entityClass.getDeclaredField(fieldName);
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            return field.get(entity);
        } catch (Exception e) {
            throw new SystemException();
        }
    }

    private boolean hasRecord(String id) {
        String sql = "SELECT COUNT(0) FROM " + tableName + " WHERE id=?";
        return sqlHelper.queryCount(sql, id) > 0;
    }

    public T get(String id, String... fieldNames) {
        String sql = "SELECT ";
        if (fieldNames.length > 0) {
            sql += fieldNames[0];
            for (int i = 1; i < fieldNames.length; i++) {
                sql += "," + fieldNames[i];
            }
        } else {
            sql += "*";
        }
        sql += " from " + tableName + " WHERE id= ? ";
        return getBySql(sql, id);
    }

    public T getBySql(String sql, Object... args) {
        List<T> list = sqlHelper.query(entityClass, sql, args);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    public void save(T entity, String... fieldNames) {
        if (entity == null || fields.size() == 0) {
            return;
        }
        List<Object> params = new ArrayList<Object>();

        String sql = "insert into " + tableName + "(";
        String valueSql = ") values(";

        if (fieldNames.length == 0) {
            Field field = fields.get(0);
            sql += field.getName();
            valueSql += "?";
            params.add(getFieldValue(field, entity));

            for (int i = 1; i < fields.size(); i++) {
                sql += "," + fields.get(i).getName();
                valueSql += ",?";
                params.add(getFieldValue(fields.get(i), entity));
            }
        } else {
            sql += fieldNames[0];
            valueSql += "?";
            params.add(getFieldValue(fieldNames[0], entity));
            for (int i = 1; i < fieldNames.length; i++) {
                sql += "," + fieldNames[i];
                valueSql += ",?";
                params.add(getFieldValue(fieldNames[i], entity));
            }
        }
        sqlHelper.execute(sql + valueSql + ")", params.toArray());
    }

    public void saveWithoutFields(T entity, String... fieldNames) {
        if (fieldNames.length == 0) {
            save(entity);
        }
        if (entity == null || fields.size() == 0) {
            return;
        }
        List<Object> params = new ArrayList<Object>();

        String sql = "insert into " + tableName + "(";
        String valueSql = ") values(";
        boolean first = true;
        boolean b;
        String fieldName = null;
        for (Field field : fields) {
            fieldName = field.getName();
            b = false;
            for (String s : fieldNames) {
                if (s.equals(fieldName)) {
                    b = true;
                    break;
                }
            }
            if (b) {
                continue;
            }
            if (first) {
                sql += field.getName();
                valueSql += "?";
                first = false;
            } else {
                sql += "," + field.getName();
                valueSql += ",?";
            }
            params.add(getFieldValue(field, entity));
        }

        sqlHelper.execute(sql + valueSql + ")", params.toArray());
    }

    public void save(List<T> entities) {
        if (entities == null || entities.size() == 0) {
            return;
        }

        for (T entity : entities) {
            save(entity);
        }
    }

    public void update(T entity, String... fieldNames) {
        Object idvalue = getIdValue(entity);
        if (entity == null || fields.size() == 0 || idvalue == null) {
            return;
        }
        String sql = "update " + tableName + " set ";
        boolean first = true;
        List<Object> params = new ArrayList<Object>();

        if (fieldNames.length > 0) {
            for (String s : fieldNames) {
                if (isPK(s)) {
                    continue;
                }
                if (first) {
                    sql += s + "=?";
                    first = false;
                } else {
                    sql += "," + s + "=?";
                }
                params.add(getFieldValue(s, entity));
            }
        } else {
            for (Field field : fields) {
                String fieldName = field.getName();
                if (isPK(fieldName)) {
                    continue;
                }
                if (first) {
                    sql += fieldName + "=?";
                    first = false;
                } else {
                    sql += "," + fieldName + "=?";
                }
                params.add(getFieldValue(field, entity));
            }
        }
        if (!first) {
            sql += " WHERE id= ? ";
            params.add(getIdValue(entity));
            sqlHelper.execute(sql, params.toArray());
        }
    }

    public void update(List<T> entities) {
        if (entities != null && entities.size() > 0) {
            for (T entity : entities) {
                update(entity);
            }
        }
    }

    public void saveOrUpdate(T entity) {
        Object object = getIdValue(entity);
        if (object != null && hasRecord(object.toString())) {
            update(entity);
        } else {
            save(entity);
        }
    }

    public void delete(String id) {
        String sql = "DELETE FROM " + tableName + " WHERE id=?";
        sqlHelper.execute(sql, id);
    }

    public void delete(T entity) {
        String sql = "DELETE FROM " + tableName + " WHERE id=?";
        sqlHelper.execute(sql, getIdValue(entity));
    }

    public void delete(List<T> entities) {
        if (entities != null && entities.size() > 0) {
            for (T entity : entities) {
                delete(entity);
            }
        }
    }

    public List<T> query(String sql, Object... args) {
        return sqlHelper.query(entityClass, sql, args);
    }

    public List<String> queryForStringList(String sql, Object... args) {
        return sqlHelper.queryForList(String.class, sql, args);
    }

    public String queryJson(String sql, Object... args) {
        return sqlHelper.queryJson(sql, args);
    }

    public String queryJson(IQueryPage page, String sql, final Object... args) {
        return sqlHelper.queryJson(page, sql, args);
    }

    protected String prepareForQueryDisplay(String id) {
        return prepareForQueryDisplay(id,null);
    }
    
    protected String prepareForQueryDisplay(String id,String nameFiled) {
        String sql = "SELECT COUNT(id) FROM " + tableName + " WHERE id=?";
        if (sqlHelper.queryCount(sql, id) == 0) {
            return null;
        }
        
        sql = "SELECT name,deleted FROM " + tableName + " WHERE id=?";
        if(!StringUtil.isNullOrEmpty(nameFiled)){
            sql = "SELECT "+nameFiled+" name,deleted FROM " + tableName + " WHERE id=?";
        }
        return sqlHelper.queryForMapJson(sql, id);
    }
}
